package com.hsmpay.common.util.jiami;

import com.hsmpay.utils.system.PbkConfig;
import it.sauronsoftware.base64.Base64;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 原来在用mac 系统中自带的openssl生成的密钥对文件是X509编码格式的。而我们JAVA所需的私钥文件是PKCS#8编码格式的。。所以要将在mac 系统中生成的私钥文件转下码就行了
 * 而安卓需要 添加Cipher cipher = Cipher.getInstance("RSA", "BC");
 * <p/>
 * 三个平台使用
 *
 * @author Administrator
 */
public class RSAObjectC {

    private static Logger log = Logger.getLogger(RSAObjectC.class);
    private static String DEFAULT_PUBLIC_KEY = PbkConfig.getAttribute("TONGYONG_PUB_KEY").trim();;
//            "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCskYbd5kRYZATRQgEucd1VVZh6" + "\r" +
//                    "GWyT+95fyuNG5kZm4AyLvJaeUd2j22oWH1aKPj1KVlCsZjw+0sw54fIN8ZWEuIbn" + "\r" +
//                    "1oeSKZzYR8aCKqCViGbn9FOpO2qPfZm2T2UnV5o6Zq5471l2LuNiwNLTDqbuw8Um" + "\r" +
//                    "njj66o/SYEOWuXBWawIDAQAB" + "\r";
//		"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvYLXcmTcjYmcq4XN4fON5OE9v" + "\r" +
//		"vQCbgMp054aEhL/DzuQeQNSr36L9UBdtjA3fRoGU26tE65tRAmzy2XYeh10wJOTr" + "\r" +
//		"QwRD2mE7hLWZAPla70KFBkWPfCYn6EMn3vQ917xjY8kklL3SrsDGRuFeW1ugz8xC" + "\r" +
//		"bJCHcUkDW0b60WBkrQIDAQAB" + "\r" ;


    private static final String DEFAULT_PRIVATE_KEY =
            "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKyRht3mRFhkBNFC" + "\r" +
                    "AS5x3VVVmHoZbJP73l/K40bmRmbgDIu8lp5R3aPbahYfVoo+PUpWUKxmPD7SzDnh" + "\r" +
                    "8g3xlYS4hufWh5IpnNhHxoIqoJWIZuf0U6k7ao99mbZPZSdXmjpmrnjvWXYu42LA" + "\r" +
                    "0tMOpu7DxSaeOPrqj9JgQ5a5cFZrAgMBAAECgYEApvJa0U21jPWmG3OJhQ8vGyEl" + "\r" +
                    "0+nIuxmNtoqnea3JKjlSqdUWua9lhuH8Lc6/gBpaXRJIFaEKY5S3cr/91jODez3q" + "\r" +
                    "Grngl/D/AMsx/NAaj30XzUAf3OObKWVTZdNERUUuxafeLM8xNbhUhS0F8AMdc8z3" + "\r" +
                    "O/u+w3HTTJ8gqdtpWuECQQDW2MMV9c/oH6GsDk9l9UCOmoNHFmQkPLV90/ws35Oj" + "\r" +
                    "tsqpYv4KP4ZbUaw7pkJkCPHzHfYAI0xw1C67GQUrGKtZAkEAzZ+a66FkxJcext0Q" + "\r" +
                    "Dz+lu1JMkE79zXVET310h6JY/xAKuqOCAw+pQcQQv8XuEi3OxnMZcfD1KFh0Zuxu" + "\r" +
                    "mutLYwJBANFtgt2JPB09mE8rs+HjbAaWP5mwDfX058W8OnlTh4tyx6LOSGyc989U" + "\r" +
                    "kdujedwhjBg9AGup/P2PF+5xuUQFTCECQBwb6HKzsnHJctSenbZn7gEIhBzqH3n5" + "\r" +
                    "wOfY75gnEmFz0POorHo8ptettNhyd1QW3QB19ZGE7g6g4PC8+3XEGp8CQDHOTLDo" + "\r" +
                    "UxB7dO3W5q2DFFjbbWNB/Fw2DRMbh6xYLrLNXoXRUByjCbKtDLuRF2PnUlMIEaV/" + "\r" +
                    "EB011IK3iTQMLYc=" + "\r";
//		"MIICXQIBAAKBgQCvYLXcmTcjYmcq4XN4fON5OE9vvQCbgMp054aEhL/DzuQeQNSr" + "\r" +
//		"36L9UBdtjA3fRoGU26tE65tRAmzy2XYeh10wJOTrQwRD2mE7hLWZAPla70KFBkWP" + "\r" +
//		"fCYn6EMn3vQ917xjY8kklL3SrsDGRuFeW1ugz8xCbJCHcUkDW0b60WBkrQIDAQAB" + "\r" +
//		"AoGBAJdFA5hTT4vlxLbn34F9t3dHar0meO+oFvje+tgy6HUsbvbpVIcrTprQCmUi" + "\r" +
//		"+JQtbHfJQeEgl8c4IGEX0RpkB6uhm0R+4s/lTqhnhEJh+ULdacYV8vaLt7e0kyjg" + "\r" +
//		"7zM4o80LJR0wk1hnZqMoQyH4+WVf7rc6/sCUjfnynZb5/FjBAkEA1f5iKt2u6Qtv" + "\r" +
//		"TpgeGvijtCxZy2hoPtRizF/maAOpXt+mcKxd3YbPMorcaqrtp3+kDIM4KfFyCFFL" + "\r" +
//		"UiszOEidVwJBANHNzJStAABXQdugzftA0hVHIsDfj3FH5mJ8l4c04/9QyvBr79jV" + "\r" +
//		"cTaCPPn3EGva+vtHMjbIjPQYxGxqpRKqR5sCQQCFse3BHEk4HkXHU7CTZz5XxdHA" + "\r" +
//		"DJX8kxK63zuDRq5dsNs6z+XBDoWK7Uiyd+IM4OksTBsd0VROMAQf7Q+OHYf3AkBc" + "\r" +
//		"JXdlFVaaz7gtLkNJxv5+OfAZphbqOhoFx5MF30UELgfz8HQ3WAeRWUJOxyR/On5h" + "\r" +
//		"PrPfO9Ysn3Ql6fD2cbNhAkAbKyAD0zl4QUHtcmwKyhTJzJbw/Jvm32orVMoSB5EB" + "\r" +
//		"2yYVTcDY/Nw6FUz8ej82sKxxHXGvfPVVr4vygppecvEm" + "\r";


    /**
     * 私钥
     */
    private RSAPrivateKey privateKey;

    /**
     * 公钥
     */
    private RSAPublicKey publicKey;

    /**
     * 字节数据转字符串专用集合
     */
    private static final char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};


    /**
     * 获取私钥
     *
     * @return 当前的私钥对象
     */
    public RSAPrivateKey getPrivateKey() {
        return privateKey;
    }

    /**
     * 获取公钥
     *
     * @return 当前的公钥对象
     */
    public RSAPublicKey getPublicKey() {
        return publicKey;
    }

    /**
     * 随机生成密钥对
     */
    public void genKeyPair() {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        keyPairGen.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
        this.privateKey = (RSAPrivateKey) keyPair.getPrivate();
        this.publicKey = (RSAPublicKey) keyPair.getPublic();
    }

    /**
     * 从文件中输入流中加载公钥
     *
     * @param in 公钥输入流
     * @throws Exception 加载公钥时产生的异常
     */
    public void loadPublicKey(InputStream in) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            loadPublicKey(sb.toString());
        } catch (IOException e) {
            throw new Exception("公钥数据流读取错误");
        } catch (NullPointerException e) {
            throw new Exception("公钥输入流为空");
        }
    }


    /**
     * 从字符串中加载公钥
     *
     * @param publicKeyStr 公钥数据字符串
     * @throws Exception 加载公钥时产生的异常
     */
    public void loadPublicKey(String publicKeyStr) throws Exception {
        try {
            log.debug("公钥：#" + new String(Base64.encode(publicKeyStr.getBytes("UTF-8")), "UTF-8"));
            BASE64Decoder base64Decoder = new BASE64Decoder();
            byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
            publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("公钥非法");
        } catch (IOException e) {
            throw new Exception("公钥数据内容读取错误");
        } catch (NullPointerException e) {
            throw new Exception("公钥数据为空");
        }
    }

    /**
     * 从文件中加载私钥
     *
     * @return 是否成功
     * @throws Exception
     */
    public void loadPrivateKey(InputStream in) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                if (readLine.charAt(0) == '-') {
                    continue;
                } else {
                    sb.append(readLine);
                    sb.append('\r');
                }
            }
            loadPrivateKey(sb.toString());
        } catch (IOException e) {
            throw new Exception("私钥数据读取错误");
        } catch (NullPointerException e) {
            throw new Exception("私钥输入流为空");
        }
    }

    public void loadPrivateKey(String privateKeyStr) throws Exception {
        try {
            log.debug("私钥：#" + new String(Base64.encode(privateKeyStr.getBytes("UTF-8")), "UTF-8"));
            BASE64Decoder base64Decoder = new BASE64Decoder();
            byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("私钥非法");
        } catch (IOException e) {
            throw new Exception("私钥数据内容读取错误");
        } catch (NullPointerException e) {
            throw new Exception("私钥数据为空");
        }
    }

    /**
     * 加密过程
     *
     * @param publicKey     公钥
     * @param plainTextData 明文数据
     * @return
     * @throws Exception 加密过程中的异常信息
     */
    public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
        if (publicKey == null) {
            throw new Exception("加密公钥为空, 请设置");
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] output = cipher.doFinal(plainTextData);
            return output;
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此加密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("加密公钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("明文数据已损坏");
        }
    }

    /**
     * 加密过程 没有用安卓补位
     *
     * @param publicKey     公钥
     * @param plainTextData 明文数据
     * @return
     * @throws Exception 加密过程中的异常信息
     */
    public byte[] encryptNew(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
        if (publicKey == null) {
            throw new Exception("加密公钥为空, 请设置");
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] output = cipher.doFinal(plainTextData);
            return output;
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此加密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("加密公钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("明文数据已损坏");
        }
    }

    /**
     * 解密过程
     *
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return 明文
     * @throws Exception 解密过程中的异常信息
     */
    public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
        if (privateKey == null) {
            throw new Exception("解密私钥为空, 请设置");
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] output = cipher.doFinal(cipherData);
            return output;
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此解密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("解密私钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("密文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("密文数据已损坏");
        }
    }

    /**
     * 解密过程  没有用安卓补位
     *
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return 明文
     * @throws Exception 解密过程中的异常信息
     */
    public byte[] decryptNew(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
        if (privateKey == null) {
            throw new Exception("解密私钥为空, 请设置");
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] output = cipher.doFinal(cipherData);
            return output;
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此解密算法");
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("解密私钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("密文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("密文数据已损坏");
        }
    }


    /**
     * 字节数据转十六进制字符串
     *
     * @param data 输入数据
     * @return 十六进制内容
     */
    public static String byteArrayToString(byte[] data) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < data.length; i++) {
            //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
            stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
            //取出字节的低四位 作为索引得到相应的十六进制标识符
            stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
            if (i < data.length - 1) {
                stringBuilder.append(' ');
            }
        }
        return stringBuilder.toString();
    }

    private RSAObjectC() {

    }

    public static RSAObjectC getInstance() {
        RSAObjectC rsaEncrypt = new RSAObjectC();

        //加载公钥
        try {
            rsaEncrypt.loadPublicKey(RSAObjectC.DEFAULT_PUBLIC_KEY);
            log.debug("加载公钥成功");
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.err.println("加载公钥失败");
        }

        //加载私钥
        try {
            rsaEncrypt.loadPrivateKey(RSAObjectC.DEFAULT_PRIVATE_KEY);
            log.debug("加载私钥成功");
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.err.println("加载私钥失败");
        }
        return rsaEncrypt;
    }

    public static RSAObjectC getInstance(String publicKey, String privateKey) {
        RSAObjectC rsaEncrypt = new RSAObjectC();

        //加载公钥
        try {
            rsaEncrypt.loadPublicKey(publicKey);
            log.debug("加载公钥成功");
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.err.println("加载公钥失败");
        }

        //加载私钥
        try {
            rsaEncrypt.loadPrivateKey(privateKey);
            log.debug("加载私钥成功");
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.err.println("加载私钥失败");
        }
        return rsaEncrypt;
    }

}
